package Method_01;

public class PollGroup<T extends Comparable<T>> extends ThreadGroup {

	/* */
	private PollableNode<T> head;
	private PollableNode<T> tail;
	/* *
	PollableNode<T> head;
	PollableNode<T> tail;
	/* */
	
	private Poll<T> poll;
	private PollableNode<T> response;
	private boolean atBeginning = false, atEnd = false;
	
	public PollGroup(String name) {
		super(name);
	}
	
	/**
	 * Get the current poll
	 * 		- Note, it will only exist for a short amount of time
	 * 		- Usually only used by the PollableNodes
	 * 
	 * @return The current Poll
	 */
	public Poll<T> getPoll(){
		return poll;
	}
	
	/**
	 * Returns the response from the last poll
	 * 		- Used by makePoll(), don't usually need to call this
	 * 
	 * @return PollableNode
	 */
	public PollableNode<T> getResponse(){
		return response;
	}
	
	/**
	 * Sets the response to the most recent Poll
	 * 		- Used by the PollableNodes
	 * 
	 * @param r : PollableNode that is the response to the most recent Poll
	 */
	public void setResponse(PollableNode<T> r){
		response = r;
	}
	
	/**
	 * Set the flag to say that the node goes at the beginning
	 * 		- Should be set by the head node when doing a to the left check
	 */
	public void atBeginning(){
		atBeginning = true;
	}
	
	/**
	 * Set the flag to say that the node goes at the end
	 * 		- Should be set by the tail node when doing a to the right check
	 */
	public void atEnd(){
		atEnd = true;
	}
	
	/**
	 * Start a Poll and return the response
	 * 
	 * @param p : Custom Poll
	 * 
	 * @return PollableNode that is the response to the Poll
	 */
	public PollableNode<T> makePoll(Poll<T> p){
		atBeginning = false;
		atEnd = false;
		poll = p;
		long i = 0;
		while (i < 10000000l && response==null && !atBeginning && !atEnd){
			i++;
		}
		poll = null;
		
		return response;
	}
	
	
	public void add(T value){
		add(new PollableNode<T>(this,value));
	}
	
	/**
	 * Add a PollableNode to the stuff yeah, oh and start it
	 * 
	 * @param node
	 */
	public void add(PollableNode<T> node){
		if (head == null){
			head = node;
			tail = node;
		} else {
			PollableNode<T> tempR = makePoll(new ToTheRightOf(node));
			
			// if the node doesn't have any to the right of it
			if (tempR == null){
				node.left = tail;
				tail.right = node;
				tail = node;
			} else {
				// there is an element to the right
				node.right = tempR;
				PollableNode<T> tempL = tempR.left;
				tempR.left = node;
				
				// no element to the left
				if (tempL == null){
					head = node;
				} else {
					// is an element to the left
					tempL.right = node;
					node.left = tempL;
				}
			}
		}
		
		node.start();
	}
	
	// TODO: implement this should be easy
	public void remove(){
		
	}
	
	public PollableNode<T> getHead(){
		return head;
	}
	
	public PollableNode<T>getTail(){
		return tail;
	}
	
	public Poll<T> ToTheLeftOf(PollableNode<T> pn){
		return ToTheLeftOf(pn.getValue());
	}
	
	public Poll<T> ToTheLeftOf(T Value){
		/**
		 * Find the node just to the left of where this value should be
		 * 
		 * @author whitehts
		 *
		 */
		class ToTheLeftOf extends Poll<T> {
			T value;
			
			public ToTheLeftOf(T value){
				this.value = value;
			}
			@Override
			public int isSuccess(PollableNode<T> pn) {
				// if this is the farthest left element, and is to the right of the value, the value goes at the beginning
				if (pn.left == null && pn.compareTo(value) > 0)
					return -1;
				
				// isn't the farthest right node
				if (pn.right != null)
					// if this node is to the left of, or the same  as the value, but it's right neighbor is to the right of the value
					return (pn.compareTo(value) <= 0 && pn.right.compareTo(value) > 0)?1:0;
				
				// is the farthest right node, and is to the left of the value
				if (pn.compareTo(value) < 0)
					return 1;
				
				return 0;
			}
		}
		
		return new ToTheLeftOf(Value);
	}
	
	/* *
	public Poll<T> ToTheRightOf(PollableNode<T> pn){
		return ToTheRightOf(pn.getValue());
	}
	
	
	public Poll<T> ToTheRightOf(T Value){
		/**
		 * Find the node just to the right of where this value should be
		 * 
		 * @author whitehts
		 *
		 *
		class ToTheRightOf extends Poll<T> {
			T value;
			
			public ToTheRightOf(T value){
				this.value = value;
			}
			@Override
			public int isSuccess(PollableNode<T> pn) {
				// if this is the farthest right node, and is to the left or the same as the value, the value goes on the end
				if (pn.right == null && pn.compareTo(value) <= 0 )
					return 2;
				
				// isn't the farthest left value
				if (pn.left != null)
					// it is to the right or same as the value, and it's left neighbor is to the left of the value
					return (pn.compareTo(value) >= 0 && pn.left.compareTo(value) < 0)?1:0;
				
				// is the farthest left value, and is to the right or the same as the value
				if (pn.compareTo(value) >= 0)
					return 1;
				
				
				
				return 0;
			}
		}
		
		return new ToTheRightOf(Value);
	}
	/* */
	
	public class ToTheRightOf extends Poll<T> {
		T value;
		
		public ToTheRightOf(T value){
			this.value = value;
		}
		
		public ToTheRightOf(PollableNode<T> node){
			value = node.getValue();
		}
		
		@Override
		public int isSuccess(PollableNode<T> pn) {
			// if this is the farthest right node, and is to the left or the same as the value, the value goes on the end
			if (pn.right == null && pn.compareTo(value) <= 0 )
				return 2;
			
			// isn't the farthest left value
			if (pn.left != null)
				// it is to the right or same as the value, and it's left neighbor is to the left of the value
				return (pn.compareTo(value) >= 0 && pn.left.compareTo(value) < 0)?1:0;
			
			// is the farthest left value, and is to the right or the same as the value
			if (pn.compareTo(value) >= 0)
				return 1;
			
			
			
			return 0;
		}
	}
	
	public String toString(){
		String result = "[";
		PollableNode<T> temp = head;
		while (temp != null){
			result += temp + ", ";
			temp = temp.right;
		}
		return result.substring(0, result.length()-2) + "]";
	}

}
